package com.xbjtech.gson;

import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.DecimalFormat;
//import java.text.NumberFormat;
//import java.util.Map;
//import java.util.Map.Entry;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.converter.json.GsonBuilderUtils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
//import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

public class CustomGsonFactoryBean implements FactoryBean<Gson>, InitializingBean {
	
	private boolean base64EncodeByteArrays = false;
	private boolean serializeNulls = false;
	private boolean prettyPrinting = false;
	private boolean disableHtmlEscaping = false;
	private String dateFormatPattern;
	private Gson gson;
	private boolean nullToEmpty = false;
	private String bigDecimalFormatPatten;
//	private Map<Class<Object>, JsonSerializer<Object>> serializerTypeAdapters;
//	private Map<Class<Object>, JsonDeserializer<Object>> deserializerTypeAdapters;
	
	
	@Override
	public void afterPropertiesSet() {
		GsonBuilder builder = (this.base64EncodeByteArrays ?
				GsonBuilderUtils.gsonBuilderWithBase64EncodedByteArrays() : new GsonBuilder());
		if (this.serializeNulls) {
			builder.serializeNulls();
		}
		if (this.prettyPrinting) {
			builder.setPrettyPrinting();
		}
		if (this.disableHtmlEscaping) {
			builder.disableHtmlEscaping();
		}
		if (this.nullToEmpty) {
			builder.registerTypeAdapter(String.class, new TypeAdapter<String>() {
				@Override
				public void write(JsonWriter out, String value) throws IOException {
					if (value == null) {
						out.value("");
						return;
					}
					out.value(value);
				}
				@Override
				public String read(JsonReader in) throws IOException {
					if (in.peek() == JsonToken.NULL) {
						in.nextNull();
						return "";
					}
					return in.nextString();
				}
			});
		}
		if (this.dateFormatPattern != null) {
			builder.setDateFormat(this.dateFormatPattern);
		}
		if (this.bigDecimalFormatPatten != null) {
			builder.registerTypeAdapter(BigDecimal.class, new JsonSerializer<BigDecimal>() {
				@Override
				public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) {
					DecimalFormat nf = new DecimalFormat(bigDecimalFormatPatten);
					String format = nf.format(src);
					return context.serialize(format);
				}
			});
		}
//		if (this.getSerializerTypeAdapters() != null && !this.getSerializerTypeAdapters().isEmpty()) {
//			for (Entry<Class<Object>, JsonSerializer<Object>> entry : this.getSerializerTypeAdapters().entrySet()) {
//				builder.registerTypeAdapter(entry.getKey(), entry.getValue());
//			}
//		}
//		if (this.getDeserializerTypeAdapters() != null && !this.getDeserializerTypeAdapters().isEmpty()) {
//			for (Entry<Class<Object>, JsonDeserializer<Object>> entry : this.getDeserializerTypeAdapters().entrySet()) {
//				builder.registerTypeAdapter(entry.getKey(), entry.getValue());
//			}
//		}
		this.gson = builder.create();
	}


//	public Map<Class<Object>, JsonSerializer<Object>> getSerializerTypeAdapters() {
//		return serializerTypeAdapters;
//	}
//
//
//	public void setSerializerTypeAdapters(Map<Class<Object>, JsonSerializer<Object>> serializerTypeAdapters) {
//		this.serializerTypeAdapters = serializerTypeAdapters;
//	}
//
//
//	public Map<Class<Object>, JsonDeserializer<Object>> getDeserializerTypeAdapters() {
//		return deserializerTypeAdapters;
//	}
//
//
//	public void setDeserializerTypeAdapters(Map<Class<Object>, JsonDeserializer<Object>> deserializerTypeAdapters) {
//		this.deserializerTypeAdapters = deserializerTypeAdapters;
//	}
	
	@Override
	public Gson getObject() {
		return this.gson;
	}
	
	public void setBase64EncodeByteArrays(boolean base64EncodeByteArrays) {
		this.base64EncodeByteArrays = base64EncodeByteArrays;
	}

	public void setSerializeNulls(boolean serializeNulls) {
		this.serializeNulls = serializeNulls;
	}

	public void setPrettyPrinting(boolean prettyPrinting) {
		this.prettyPrinting = prettyPrinting;
	}

	public void setDisableHtmlEscaping(boolean disableHtmlEscaping) {
		this.disableHtmlEscaping = disableHtmlEscaping;
	}

	public void setDateFormatPattern(String dateFormatPattern) {
		this.dateFormatPattern = dateFormatPattern;
	}
	
	@Override
	public Class<?> getObjectType() {
		return Gson.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
	
	public void setNullToEmpty(boolean nullToEmpty) {
		this.nullToEmpty = nullToEmpty;
	}


	public String getBigDecimalFormatPatten() {
		return bigDecimalFormatPatten;
	}


	public void setBigDecimalFormatPatten(String bigDecimalFormatPatten) {
		this.bigDecimalFormatPatten = bigDecimalFormatPatten;
	}
	
}
